package org.cytoscape.cytargetlinker.internal.view;

import java.awt.Color;
import java.awt.Paint;

import org.cytoscape.cytargetlinker.internal.CTLManager;
import org.cytoscape.cytargetlinker.internal.model.RegNet;
import org.cytoscape.cytargetlinker.internal.util.Preferences;
import org.cytoscape.view.presentation.property.ArrowShapeVisualProperty;
import org.cytoscape.view.presentation.property.BasicVisualLexicon;
import org.cytoscape.view.presentation.property.NodeShapeVisualProperty;
import org.cytoscape.view.presentation.property.values.ArrowShape;
import org.cytoscape.view.presentation.property.values.NodeShape;
import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
import org.cytoscape.view.vizmap.VisualMappingManager;
import org.cytoscape.view.vizmap.VisualStyle;
import org.cytoscape.view.vizmap.VisualStyleFactory;
import org.cytoscape.view.vizmap.mappings.DiscreteMapping;
import org.cytoscape.view.vizmap.mappings.PassthroughMapping;

/**
 * visual style of the CyTargetLinker plugin
 * network nodes are grey, round nodes
 * new nodes are pink, rounded rectangle nodes
 * edges are colored based on the RIN that contained the regulatory interaction
 */
public class CTLVisualStyle {

	private String nodeTypeAttr;
	private String networkNodeValue;
	private String newNodeValue;
	private String groupNodeValue;
	
	private VisualStyle vs;
	private CTLManager manager;
	
	/**
	 * creates the CyTargetLinker visual style
	 */
	public CTLVisualStyle(CTLManager manager, VisualStyleFactory visualStyleFactory, 
			VisualMappingManager visualMappingMgr, 
			VisualMappingFunctionFactory discreteMappingFactory, 
			VisualMappingFunctionFactory continuousMappingFactory,
			VisualMappingFunctionFactory passThroughMappingFactory) {
		
		this.manager = manager;
		vs = visualStyleFactory.createVisualStyle(Preferences.getInstance().getVsName());
		nodeTypeAttr = Preferences.getInstance().getNodeTypeAttribute();
		networkNodeValue = Preferences.getInstance().getNetworkNodeValue();
		newNodeValue = Preferences.getInstance().getNewNodeValue();
		groupNodeValue = Preferences.getInstance().getGroupNodeValue();
		

		defineLabel(passThroughMappingFactory);
		defineNodeBorder(discreteMappingFactory);
		defineNodeColor(discreteMappingFactory);
		defineNodeShape(discreteMappingFactory);
		defineNodeSize(discreteMappingFactory);
		defineEdgeArrow(discreteMappingFactory);
		defineEdgeColor(discreteMappingFactory);
		
		visualMappingMgr.addVisualStyle(vs);		
	}
	
	public VisualStyle getVisualStyle() {
		return vs;
	}
	
	/**
	 * defines node label for all nodes
	 */
	private void defineLabel(VisualMappingFunctionFactory passThroughMapping) {
		PassthroughMapping<String, String> nodeLabelMapping =
				(PassthroughMapping<String, String>) passThroughMapping.
				createVisualMappingFunction("label", String.class, BasicVisualLexicon.NODE_LABEL);
		
		vs.addVisualMappingFunction(nodeLabelMapping);
	}
	
	/**
	 * defines node border for new and existing nodes
	 */
	private void defineNodeBorder(VisualMappingFunctionFactory discreteMapping) {
		DiscreteMapping<String, Paint> nodeBorderMapping = 
				(DiscreteMapping<String, Paint>) discreteMapping.
				createVisualMappingFunction(nodeTypeAttr, String.class, BasicVisualLexicon.NODE_BORDER_PAINT);
		
		nodeBorderMapping.putMapValue(newNodeValue, Color.darkGray);
		nodeBorderMapping.putMapValue(networkNodeValue, Color.darkGray);
		
		vs.addVisualMappingFunction(nodeBorderMapping);
	}
	
	/**
	 * defines node color
	 * new node -> pink
	 * existing node -> light gray
	 * group node -> white
	 */
	private void defineNodeColor(VisualMappingFunctionFactory discreteMapping) {
		DiscreteMapping<String, Paint> nodeColorMapping = 
				(DiscreteMapping<String, Paint>)discreteMapping.
				createVisualMappingFunction(nodeTypeAttr, String.class, BasicVisualLexicon.NODE_FILL_COLOR);
		
		nodeColorMapping.putMapValue(newNodeValue, Color.pink);
		nodeColorMapping.putMapValue(networkNodeValue, Color.LIGHT_GRAY);
		nodeColorMapping.putMapValue(groupNodeValue, Color.WHITE);
		
		vs.addVisualMappingFunction(nodeColorMapping);
	}
	
	/**
	 * defines node shape
	 * new nodes -> rounded rectangle
	 * existing nodes -> ellipse
	 * group nodes -> triangle
	 */
	private void defineNodeShape(VisualMappingFunctionFactory discreteMapping) {
		DiscreteMapping<String, NodeShape> nodeShapeMapping = (DiscreteMapping<String, NodeShape>) discreteMapping.
				createVisualMappingFunction(nodeTypeAttr, String.class, BasicVisualLexicon.NODE_SHAPE);
		
		nodeShapeMapping.putMapValue(newNodeValue, NodeShapeVisualProperty.ROUND_RECTANGLE);
		nodeShapeMapping.putMapValue(networkNodeValue, NodeShapeVisualProperty.ELLIPSE);
		nodeShapeMapping.putMapValue(groupNodeValue, NodeShapeVisualProperty.TRIANGLE);

		vs.addVisualMappingFunction(nodeShapeMapping);
	}
	
	/**
	 * makes sure that group nodes are smaller 
	 */
	private void defineNodeSize(VisualMappingFunctionFactory discreteMapping) {
		DiscreteMapping<String, Double> nodeSizeMapping = (DiscreteMapping<String, Double>) discreteMapping.
				createVisualMappingFunction(nodeTypeAttr, String.class, BasicVisualLexicon.NODE_SIZE);
		
		nodeSizeMapping.putMapValue(groupNodeValue, 5.0);

		vs.addVisualMappingFunction(nodeSizeMapping);
	}
	
	/**
	 * target interactions have an arrow shape
	 */
	private void defineEdgeArrow(VisualMappingFunctionFactory discreteMapping) {
		DiscreteMapping<String, ArrowShape> edgeArrowMapping = (DiscreteMapping<String, ArrowShape>) discreteMapping.
				createVisualMappingFunction("interaction", String.class, BasicVisualLexicon.EDGE_TARGET_ARROW_SHAPE);
		
		edgeArrowMapping.putMapValue("pp", ArrowShapeVisualProperty.CIRCLE);
		edgeArrowMapping.putMapValue("interaction", ArrowShapeVisualProperty.ARROW);
		
		for(RegNet net : manager.getRins()) {
			edgeArrowMapping.putMapValue(net.getName(), ArrowShapeVisualProperty.ARROW);
		}
		
		edgeArrowMapping.putMapValue("Line, Arrow", ArrowShapeVisualProperty.ARROW);
		edgeArrowMapping.putMapValue("Line, TBar", ArrowShapeVisualProperty.T);
		edgeArrowMapping.putMapValue("group-connection", ArrowShapeVisualProperty.NONE);
		
		vs.addVisualMappingFunction(edgeArrowMapping);
	}
	
	/**
	 * defines the color of the edge and arrows
	 * everything is black except the new errors
	 * they are colored differently
	 */
	private void defineEdgeColor(VisualMappingFunctionFactory discreteMapping) {
		DiscreteMapping<String, Paint> edgeColorMapping = (DiscreteMapping<String, Paint>) discreteMapping.
				createVisualMappingFunction("interaction", String.class, BasicVisualLexicon.EDGE_PAINT);
		
		// TODO: add edge color to all regulatory interaction networks
		// different Edge colors according to the RIN and preferences
		for(RegNet net : manager.getRins()) {
			edgeColorMapping.putMapValue(net.getName(), net.getColor());
		}
		
		edgeColorMapping.putMapValue("interaction", Color.BLACK);
		edgeColorMapping.putMapValue("pp", Color.BLACK);
		edgeColorMapping.putMapValue("Line, Arrow", Color.BLACK);
		edgeColorMapping.putMapValue("Line, TBar", Color.BLACK);
		edgeColorMapping.putMapValue("group-connection", Color.BLACK);
		
		vs.addVisualMappingFunction(edgeColorMapping);
	}
}
